package fileutils

import (
	"errors"
	"fmt"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"

	"gitlab.local/golibrary/utils"
)

var (
	EXT4                  string = "ext4"
	BTRFS                 string = "btrfs"
	TMPFS                 string = "tmpfs"
	ErrMountpointNotFound error  = errors.New("ErrMountpointNotFound")
)

// Mountpoint 获取路径所在挂载点
func Mountpoint(path string) string {
	path, _ = filepath.Abs(path)
	linuxCmd := `df "%s" | tail -1 | awk '{print $6}'`
	res, err := utils.ShellExec(fmt.Sprintf(linuxCmd, path))
	if err == nil && len(strings.TrimSpace(res)) > 0 {
		return strings.TrimSpace(res)
	}
	return Mountpoint(filepath.Dir(path))
}

// DetermineType 判断 {mountpoint} 的文件系统
func DetermineType(mountpoint string) (string, error) {
	res, err := utils.ShellExec("mount | awk '{print $3,$5}'")
	if err != nil {
		return "", err
	}
	for _, keyValue := range strings.Split(res, "\n") {
		kv := strings.Split(keyValue, " ")
		if filepath.Join(kv[0], "/") == filepath.Join(mountpoint, "/") {
			return kv[1], nil
		}
	}
	return "", ErrMountpointNotFound
}

// DiskSpaceUsage 获取硬盘使用量
func DiskSpaceUsage(mountpoint string) (used, available int64, err error) {
	linuxCmd := `df "%s" | tail -1 | awk '{print $6,$3,$4}'`
	res, err := utils.ShellExec(fmt.Sprintf(linuxCmd, mountpoint))
	if err != nil {
		return 0, 0, err
	}
	kv := strings.Split(strings.TrimSpace(res), " ")
	used, _ = strconv.ParseInt(kv[1], 10, 64)
	used *= 1024
	available, _ = strconv.ParseInt(kv[2], 10, 64)
	available *= 1024
	return
}

// QueryQuota 查询文件系统配额
// err 为 ErrMountpointNotFound 或 available 为 -1 时表示无限额
func QueryQuota(user, mountpoint string) (used, available int64, err error) {
	linuxCmd := "quota -u %s -v --format=vfsv1 -w --hide-device --show-mntpoint -l | awk '{print $1,$2,$4}'"
	res, err := utils.ShellExec(fmt.Sprintf(linuxCmd, user))
	if err != nil {
		return 0, 0, err
	}
	for _, keyValue := range strings.Split(res, "\n") {
		kv := strings.Split(keyValue, " ")
		if filepath.Join(kv[0], "/") != filepath.Join(mountpoint, "/") {
			continue
		}

		used, err = strconv.ParseInt(strings.Trim(kv[1], "*"), 10, 64)
		if err != nil {
			continue
		}
		if strings.Contains(kv[1], "*") {
			return
		}
		available, err = strconv.ParseInt(kv[2], 10, 64)
		if err != nil {
			continue
		}
		if available != 0 {
			available = (available - used) * 1024
		} else {
			available = -1
		}
		used = used * 1024
		return
	}
	return 0, 0, ErrMountpointNotFound
}

// IsXfsVolume 判断路径是否为xfs卷
func IsXfsVolume(path string) bool {
	str := regexp.MustCompile(`^/Volume\d+($|/)`).FindString(path)
	if str == "" {
		return false
	}
	str = "/" + strings.Trim(str, "/")
	res, _ := utils.ShellExec(fmt.Sprintf(`df-json | grep '%s$' | grep xfs`, str))
	return strings.TrimSpace(res) != ""
}
